package com.sql.mysql.sharding.mapper;

import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

import com.sql.mysql.sharding.annotation.ShardingKeyObject;
import com.sql.mysql.sharding.annotation.ShardingKeyType;
import com.sql.mysql.sharding.reflection.ShardingReflectionHelper;
import com.sql.mysql.sharding.threadlocal.ShardingThreadLocal;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class ShardingTransactionMapperProxy implements InvocationHandler, Serializable {
	private static final long serialVersionUID = -555649409761687656L;

	private Object object;

	public ShardingTransactionMapperProxy(Object obj) {
		object = obj;
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		// 如果是执行普通的方法,比如toString(),比如触发日志打印就会失败
		{
			if (Object.class.equals(method.getDeclaringClass())) {
				return method.invoke(this, args);
			}
		}
		// 执行业务具体的方法,什么 CRUD操作皆在此
		// 这里才是我要的东西
		{
			// 清除本事务上一次的部分操作,只保留部分信息,这1行代码非常重要
			ShardingThreadLocal.reset(false, true);
			log.debug("清除了所有线程变量" + System.currentTimeMillis());
			// 安装ShardingKeyObject
			ShardingKeyObject shardingKey = ShardingReflectionHelper.getCopiedShardingKeyObject(method);
			if (null == shardingKey) {
				throw new Exception("fail to find sharding key for method " + method);
			}
			// [预处理]如果是参数下标指定法则,则现在就需要立刻赋值
			if (ShardingKeyType.PARAMETER_INDEX == shardingKey.getAnnotationType()) {
				shardingKey.setValue(args[shardingKey.getParameterIndex()]);
			}
			// 一定要保存
			ShardingThreadLocal.ShardingKeyObjectThreadLocal.set(shardingKey);
		}
		// 继续处理
		return method.invoke(object, args);
	}
}
